package spring.cloud.eurekaclientproduct;

import io.github.resilience4j.bulkhead.Bulkhead;
import io.github.resilience4j.bulkhead.BulkheadConfig;
import io.github.resilience4j.bulkhead.BulkheadRegistry;
import io.github.resilience4j.circuitbreaker.CircuitBreakerConfig;
import io.github.resilience4j.circuitbreaker.CircuitBreakerRegistry;
import io.github.resilience4j.circuitbreaker.autoconfigure.CircuitBreakerAutoConfiguration;
import io.github.resilience4j.circuitbreaker.autoconfigure.CircuitBreakerMetricsAutoConfiguration;
import io.github.resilience4j.ratelimiter.RateLimiterConfig;
import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.github.resilience4j.ratelimiter.autoconfigure.RateLimiterAutoConfiguration;
import io.github.resilience4j.ratelimiter.autoconfigure.RateLimiterMetricsAutoConfiguration;
import io.github.resilience4j.retry.RetryConfig;
import io.github.resilience4j.retry.RetryRegistry;
import io.github.resilience4j.timelimiter.TimeLimiterConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.client.loadbalancer.LoadBalanced;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.time.Duration;

@SpringBootApplication(exclude = {CircuitBreakerAutoConfiguration.class,
        CircuitBreakerMetricsAutoConfiguration.class,
        RateLimiterAutoConfiguration.class,
        RateLimiterMetricsAutoConfiguration.class})
@EnableEurekaClient
@EnableCircuitBreaker
public class EurekaClientProductApplication {

    public static void main(String[] args) {

        SpringApplication.run(EurekaClientProductApplication.class, args);
    }

    @LoadBalanced
    @Bean("restTemplate")
    public RestTemplate initRestTemplate(){
        return new RestTemplate();
    }


    private CircuitBreakerConfig circuitBreakerConfig;
    private CircuitBreakerRegistry circuitBreakerRegistry;

    /**
     * 断路器初始化配置
     * @return
     */
    @Bean(name = "circuitBreakConfig")
    public CircuitBreakerConfig initCircuitBreakerConfig(){
        if(circuitBreakerConfig == null){
            circuitBreakerConfig = CircuitBreakerConfig.custom()
                    //请求失败比例达到30%,打开断路器
                    .failureRateThreshold(30)
                    //断路器打开时,等待多长时间转为半开状态
                    .waitDurationInOpenState(Duration.ofSeconds(5))
                    //断路器半开状态时环形位缓冲区大小
                    .ringBufferSizeInHalfOpenState(5)
                    //断路器闭合时环形位缓冲区大小
                    .ringBufferSizeInClosedState(5)
                    //断路器异常处理
                    .recordFailure(ex->{
                        System.out.println("发生了异常,栈追踪信息为:");
                        ex.printStackTrace();
                        return false;
                    })
                    //忽略哪些异常
                    .ignoreExceptions(ClassNotFoundException.class, IOException.class)
                    //触发异常
                    .recordExceptions(Exception.class,RuntimeException.class)
                    //构建配置
                    .build();
        }
        return circuitBreakerConfig;
    }

    /**
     * 断路器构建注册机
     * @return
     */
    @Bean(name = "circuitBreakerRegistry")
    public CircuitBreakerRegistry initCircuitBreakerRegistry(){
        if(circuitBreakerConfig == null){
            initCircuitBreakerConfig();
        }
        //创建断路器注册机
        if(circuitBreakerRegistry == null){
            circuitBreakerRegistry = CircuitBreakerRegistry.of(circuitBreakerConfig);
        }
        return circuitBreakerRegistry;
    }


    //限速器
    private RateLimiterConfig rateLimiterConfig;
    private RateLimiterRegistry rateLimiterRegistry;

    /**创建限速器配置
     *
     * @return
     */
    @Bean(name = "rateLimiterConfig")
    public RateLimiterConfig initRateLimiterConfig(){
        if(rateLimiterConfig ==  null){
            //自定义限制 20 req/s 的限速器  req代表请求的意识 1秒20次请求
            rateLimiterConfig = RateLimiterConfig.custom()
                    //配置时间戳,默认值为500纳秒
                    .limitRefreshPeriod(Duration.ofSeconds(1))
                    //时间戳内限制通过的请求次数,默认为50
                    .limitForPeriod(20)
                    //配置超时,如果等待超时则限速器丢弃请求,默认值为5秒
                    .timeoutDuration(Duration.ofSeconds(2))
                    //构建配置
                    .build();
        }
        return rateLimiterConfig;
    }

    /** 创建限速器 注册机
     *
     * @return
     */
    @Bean(name = "rateLimiterRegistry")
    public RateLimiterRegistry initRateLimiterRegistry(){
        if(rateLimiterConfig == null){
            initRateLimiterConfig();
        }
        if(rateLimiterRegistry == null){
            //设置默认的限速器配置,创建限速器注册机
            rateLimiterRegistry = RateLimiterRegistry.of(rateLimiterConfig);
            //创建断路器,并注册在注册机内(使用默认配置)
            rateLimiterRegistry.rateLimiter("user");
        }
        return rateLimiterRegistry;
    }

    //舱壁注册机
    private BulkheadRegistry bulkheadRegistry;
    //舱壁配置
    private BulkheadConfig bulkheadConfig;

    //舱壁的配置
    @Bean(name = "bulkheadConfig")
    public BulkheadConfig initBulkheadConfig(){
        if(bulkheadConfig == null){

            bulkheadConfig = BulkheadConfig.custom()
                    //最大并发数,默认值Wie25
                    .maxConcurrentCalls(20)
                    //调度线程最大等待时间(单位毫秒),默认值为0
                    /**
                     * 如果存在高并发场景,强烈建议设置为0
                     * 如果不设置为0,那么在高并发场景下
                     * 可能会导致线程积压,引发各类问题
                     */
                    .maxWaitDuration(Duration.ofSeconds(0))
                    //构建编译
                    .build();
        }
        return bulkheadConfig;
    }

    @Bean("bulkheadRegistry")
    public BulkheadRegistry initBulkheadRegistry(){
        //创建舱壁配置
        if(bulkheadConfig == null){
            initBulkheadConfig();
        }
        //创建舱壁注册机
        if(bulkheadRegistry == null){
            //创建舱壁注册机,并设置默认配置
            bulkheadRegistry = BulkheadRegistry.of(bulkheadConfig);
            //创建一个命名为user的舱壁
            bulkheadRegistry.bulkhead("user");
        }
        return bulkheadRegistry;
    }

    //重试配置
    private RetryConfig retryConfig;
    //重试注册机
    private RetryRegistry retryRegistry;

    @Bean(name = "retryConfig")
    public RetryConfig initRetryConfig(){
        if(retryConfig == null){
            //自定义重试器配置
            retryConfig =  RetryConfig.custom()
                    //最大尝试次数,(默认为3次)
                    .maxAttempts(5)
                    //重试时间间隔(默认为500毫秒)
                    .waitDuration(Duration.ofSeconds(1))
                    //构建配置
                    .build();
        }
        return retryConfig;
    }

    @Bean(name = "retryRegistry")
    public RetryRegistry initRetryRegistry(){
        if(retryConfig == null){
            initRetryConfig();
        }
        if(retryRegistry == null){
            retryRegistry = RetryRegistry.of(retryConfig);
            retryRegistry.retry("exp");
        }
        return retryRegistry;
    }



    //创建时间限制器配置
    @Bean(name = "timeLimiter")
    public TimeLimiterConfig initTimeLimiterConfig(){

        TimeLimiterConfig timeLimiterConfig = TimeLimiterConfig.custom()
                //配置调用超时时间,默认为1秒
                .timeoutDuration(Duration.ofSeconds(2))
                //设置线程是否可中断将来再运行,默认值为true
                .cancelRunningFuture(false)
                .build();
        return timeLimiterConfig;
    }



}
